package upmc.api.aladyn.client.services.impls;

import javassist.*;
import javassist.bytecode.*;
import upmc.api.aladyn.client.annotation.XMLRMIField;
import upmc.api.aladyn.client.services.interfaces.XMLRMISerializable;

/**Service of XML-RMI
 * 
 * @author Z_WANG
 *
 * @since 1.0
 */
public class XMLRMI implements XMLRMISerializable {
	
	/**Get the content of the type #Class 
	 * 
	 * @param inter the type of #Class<?>
	 * @return the result by #String
	 */
	public static String properName(String name){
		
		if (name.equals("java.lang.String")) return "String";
		if (name.equals("I")) return "int";
		if (name.equals("Ljava/lang/String;")) return "String";
		
		
		return name;
		
	}
	
	
	public String toXML(Class<?> inter) 
	{
		StringBuffer sb = new StringBuffer();
		sb.append("<?xml version=\"1.0\">\n");
		sb.append("<methodCall>\n");
		sb.append("<methodName>"+ "" + "</methodName>\n"); // ecrire le nom de la methode appelee
		sb.append("<params>\n");
		sb.append("<param>\n");
		sb.append("<value>\n");
		sb.append("<object oid="+ ""+ ">\n");//ecrire le oid de l'objet
		ClassPool cpool = ClassPool.getDefault();
		
		
		String className = inter.getName();
		
		try {
			CtClass cc = cpool.get(className);
			
			// interfaces
			CtClass[] ccInterfaces = cc.getInterfaces();		
			if(ccInterfaces != null && ccInterfaces.length > 0)
			{
				for(int i = 0; i< ccInterfaces.length; i++)
				{
					CtClass ccInterface = ccInterfaces[i];
					sb.append(ccInterface.getName());
				}
			}
			
			// Annotations and field's value 
			
			CtField[] allCfs = cc.getDeclaredFields();
			sb.append("<fields>\n");
			for(CtField cf : allCfs)
			{
				if(cf.hasAnnotation(XMLRMIField.class))
				{
					XMLRMIField xmlrmiField =  (XMLRMIField) cf.getAnnotation(XMLRMIField.class);
					if(xmlrmiField != null)
					{
						
						sb.append("<field name>=\"" + xmlrmiField.serializationName()+"\">");
						sb.append("<value>");
						sb.append("<" + xmlrmiField.serializationType()+">");
						//sb.append(cf.);
						// ajouter la valeur du champ
						sb.append("</" + xmlrmiField.serializationType()+">");
						sb.append("</value>");
						sb.append("</field>\n");
						
						// add the infos of annotations
					}
					
				}
				
			}
			sb.append("</fields>\n");
			
			//methods
			CtMethod[] allCms = cc.getDeclaredMethods();
			sb.append("<methods>\n");
			for(CtMethod cm : allCms)
			{
				String methodName = cm.getName();
				sb.append("<method language=\"Java\">\n");
				//sb.append("public")
				//System.out.println(methodName + " "+ Modifier.toString(cm.getModifiers()));
				sb.append(Modifier.toString(cm.getModifiers()) + " " + properName(cm.getReturnType().getName()) + " " + methodName +"(");
				
				// param name
				MethodInfo methodInfo = cm.getMethodInfo();  
	            CodeAttribute codeAttribute = methodInfo.getCodeAttribute();  
	            LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute  
	                    .getAttribute(LocalVariableAttribute.tag);  
	            if (attr == null) {  
	            }  
	            String[] paramNames = new String[cm.getParameterTypes().length];
	            
	            int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;  
	            for (int i = 0; i < paramNames.length; i++)  {
	                paramNames[i] = attr.variableName(i + pos);
	                sb.append(properName(attr.descriptor(i+pos)) +" ");
	                sb.append(paramNames[i]);
	                if (i != paramNames.length -1) sb.append(", ");
	                }
	            sb.append(")\n{\n");
	            //corps de la methode
				for(CtField cf : allCfs)
				{
					if(! cf.hasAnnotation(XMLRMIField.class))
					{
						if (properName(cf.getType().getName()).equals("String")) {
							//ajouter la valeur du String du champ en question dans sb.append()
							if (cf.getName().equals("corpse_" + cm.getName()))
								sb.append(cf.getConstantValue());
							
							
						}
					
					}
				}
	            // fin du corps de la methode
	            sb.append("\n}\n");
	            sb.append("</method>\n");
	            
	            
	            //for (int i = 0; i < paramNames.length; i++) {  
	                //System.out.println("paramName" + i + ":" + paramNames[i]);  
	            //}  
			}
			sb.append("</methods>\n");
			sb.append("</object>\n");
			sb.append("</value>\n");
			sb.append("</param>\n");
			sb.append("</params>\n");
			sb.append("</methodCall>\n");
			
			//constructors			
			CtConstructor[] allCcons = cc.getConstructors();
			for(CtConstructor ccon : allCcons)
			{
				// get the informations
			}
		
		
		} catch (NotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		
		return sb.toString();
	}
	
	
	/**Update the object by the results Server returns
	 * 
	 * @param theXML #org.w3c.dom.Element
	 */
	public void updateFromXML(org.w3c.dom.Element theXML) 
	{
		
	}

}
